﻿using ShSoft.Common.PoweredByLee;
using SlamDunk.CMS.BLL;
using SlamDunk.CMS.Model;
using SlamDunk.CMS.Model.FormatModel;
using SlamDunk.CMS.Model.ViewModel;
using SlamDunk.CMS.UI.Controllers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using SlamDunk.CMS.Model.DataModel;

namespace SlamDunk.CMS.UI.Areas.Admin.Controllers
{
    /// <summary>
    /// 文章控制器
    /// </summary>
    public class ArticleController : BaseController
    {
        #region 00.实例化业务层
        /// <summary>
        /// 实例化业务层
        /// </summary>
        private readonly ArticleBll ArticleBll = new ArticleBll();
        private readonly ChannelBll ChannelBll = new ChannelBll();
        #endregion

        #region 01.加载视图
        /// <summary>
        /// 加载文章视图
        /// </summary>
        /// <param name="id">栏目Id</param>
        /// <returns>文章视图</returns>
        public ActionResult Index(int id)
        {
            this.ViewBag.ChannelId = id;
            return this.View();
        }
        #endregion

        #region 02.加载列表
        /// <summary>
        /// 加载文章列表
        /// </summary>
        /// <param name="id">栏目Id</param>
        /// <returns>文章列表</returns>
        public ActionResult List(int id)
        {
            int channelId = id;
            //1.获取EasyUI请求的数据
            int pageIndex = string.IsNullOrEmpty(this.Request["page"]) ? 1 : int.Parse(this.Request["page"]);
            int pageSize = string.IsNullOrEmpty(this.Request["rows"]) ? 15 : int.Parse(this.Request["rows"]);
            //2.查询参数处理
            DateTime startDate, endDate;
            string startTime = DateTime.TryParse(this.Request["startTime"], out startDate) ? this.Request["startTime"] : null;
            string endTime = DateTime.TryParse(this.Request["endTime"], out endDate) ? this.Request["endTime"] : null;
            string title = this.Request["title"];
            //3.调用业务层查询数据并转换视图模型返回
            int rowCount, pageCount;
            List<ArticleViewForRead> list = this.ArticleBll.GetModelList(pageIndex, pageSize, out pageCount, out rowCount, channelId, startTime, endTime, title).Select(x => x.ToViewModel()).ToList();
            //4.封装EasyUI模型
            DataGridModel dgModel = new DataGridModel()
            {
                total = rowCount,
                rows = list
            };
            //5.返回客户端数据
            return this.Json(dgModel, JsonRequestBehavior.AllowGet);
        }
        #endregion

        #region 03.添加——加载视图
        /// <summary>
        /// 添加文章视图
        /// 此处可根据类别Id不同返回不同添加视图
        /// </summary>
        /// <param name="id">栏目Id</param>
        /// <returns>添加文章视图</returns>
        public ActionResult Add(int id)
        {
            //在ViewBag中携带栏目Id
            this.ViewBag.ChannelId = id;
            //校友风采
            if (id == 12 || id == 17)
            {
                return this.View("AddPerson");
            }
            //常用下载
            if (id == 18)
            {
                return this.View("AddWithAttachment");
            }
            //教授观点
            if (id == 27)
            {
                return this.View("AddProfView");
            }
            //视频在线
            if (id == 24)
            {
                return this.View("AddVideo");
            }
            //默认视图
            return this.View();
        }
        #endregion

        #region 04.添加——提交添加
        /// <summary>
        /// 提交添加
        /// </summary>
        /// <param name="model">文章视图模型实体对象</param>
        /// <returns>添加结果</returns>
        [ValidateInput(false)]
        public ActionResult AddConfirm(ArticleViewForWrite model)
        {
            if (!this.ModelState.IsValid)
            {
                return OperateContext.Current.JsonModel(0, "您输入的数据格式有误，请重试！");
            }
            model.UserId = OperateContext.Current.CurrentUser.Id;
            Article currentModel = this.ArticleBll.Add(model.ToDataModel());
            if (currentModel != null)
            {
                //静态页处理
                this.CreateHtml(currentModel);
                return OperateContext.Current.JsonModel(1, "发布成功");
            }
            return OperateContext.Current.JsonModel(0, "发布失败，请重试！");
        }
        #endregion

        #region 05.删除一篇文章
        /// <summary>
        /// 删除一篇文章
        /// </summary>
        /// <param name="id">文章Id</param>
        /// <returns>删除结果</returns>
        public ActionResult DeleteSingle(int id)
        {
            //获取当前栏目对象
            Channel currentChannel = this.ArticleBll.GetModel(id).Channel;
            //获取静态页文件的存储路径
            string path = this.ArticleBll.GetModel(id).GetUrl();
            //此处可以自由选择物理删除或者逻辑删除，PhysicalDelete Or LogicDelete
            if (this.ArticleBll.PhysicalDelete(id))
            {
                if (!string.IsNullOrWhiteSpace(path) && System.IO.File.Exists(path))
                {
                    //删除静态页文件
                    System.IO.File.Delete(this.Server.MapPath(path));
                }
                //重写生成列表静态页
                this.RebuildListHtml(currentChannel);
                return OperateContext.Current.JsonModel(1, "删除成功！");
            }
            else
            {
                return OperateContext.Current.JsonModel(2, "删除失败，请重试！");
            }
        }
        #endregion

        #region 06.删除选中的文章
        /// <summary>
        /// 删除选中的文章
        /// </summary>
        /// <param name="selectedIds">选中文章的Id</param>
        /// <returns>删除结果</returns>
        public ActionResult DeleteSelected(string selectedIds)
        {
            try                 //涉及多次类型转换等操作，应处理异常
            {
                //1.处理前台选中的所有要删除的实体Id信息
                List<int> idList = selectedIds.Split(',').Select(x => int.Parse(x)).ToList();
                //2.获取当前栏目对象
                Channel currentChannel = this.ArticleBll.GetModel(idList[0]).Channel;
                //3.执行批量删除操作
                idList.ForEach(x =>
                {
                    string path = this.ArticleBll.GetModel(x).GetUrl();
                    if (!string.IsNullOrWhiteSpace(path) && System.IO.File.Exists(path))
                    {
                        //删除静态页文件
                        System.IO.File.Delete(this.Server.MapPath(path));
                    }
                    this.ArticleBll.PhysicalDelete(x);
                });
                //4.重新生成列表静态页
                this.RebuildListHtml(currentChannel);
                return OperateContext.Current.JsonModel(1, "删除成功！");
            }
            catch (Exception ex)
            {
                //写入日志

                //返回异常信息
                return OperateContext.Current.JsonModel(0, string.Format("删除失败，{0}", ex.Message));
            }
        }
        #endregion

        #region 07.修改——加载视图
        /// <summary>
        /// 修改文章视图
        /// 此处可根据类别Id不同返回不同修改视图
        /// </summary>
        /// <param name="id">文章Id</param>
        /// <returns>修改视图</returns>
        public ActionResult Edit(int id)
        {
            Article dataModel = this.ArticleBll.GetModel(id);
            ArticleViewForUpdate model = dataModel.ToUpdateModel();

            //修改人员视图
            if (dataModel.ChannelId == 12 || dataModel.ChannelId == 17)
            {
                return this.View("EditPerson", model);
            }
            //修改带附件的文章视图
            if (dataModel.ChannelId == 18)
            {
                return this.View("EditWithAttachment", model);
            }
            //教授观点
            if (dataModel.ChannelId == 27)
            {
                return this.View("EditProfView", model);
            }
            //添加视频
            if (dataModel.ChannelId == 24)
            {
                return this.View("EditVideo", model);
            }
            //默认视图
            return this.View(model);
        }
        #endregion

        #region 08.修改——提交修改
        /// <summary>
        /// 提交修改
        /// </summary>
        /// <param name="model">文章实体对象</param>
        /// <returns>修改结果</returns>
        [ValidateInput(false)]
        public ActionResult EditConfirm(ArticleViewForUpdate model)
        {
            if (!this.ModelState.IsValid)
            {
                return OperateContext.Current.JsonModel(0, "您输入的数据格式有误，请重试！");
            }
            model.UserId = OperateContext.Current.CurrentUser.Id;
            Article currentModel = OperateContext.Current.ToDataModel(model);
            if (this.ArticleBll.Update(currentModel))
            {
                //静态页处理
                this.CreateHtml(currentModel);
                return OperateContext.Current.JsonModel(1, "发布成功");
            }
            return OperateContext.Current.JsonModel(0, "发布失败，请重试！");
        }
        #endregion

        #region 09.管理——加载视图
        /// <summary>
        /// 管理文章视图
        /// </summary>
        /// <param name="id">文章Id</param>
        /// <returns>视图</returns>
        public ActionResult Manage(int id)
        {
            //查询文章排序并存入ViewBag
            Article model = this.ArticleBll.GetModel(id);
            this.ViewBag.Id = id;
            this.ViewBag.Sort = model.Sort;
            this.ViewBag.AddTime = model.AddTime.ToString("yyyy-MM-dd");
            return this.View();
        }
        #endregion

        #region 10.管理——提交管理
        /// <summary>
        /// 提交管理
        /// </summary>
        /// <param name="id">文章Id</param>
        /// <returns>视图</returns>
        public ActionResult ManageConfirm(int id)
        {
            int sort;//= string.IsNullOrEmpty(Request["Sort"]) ? 0 : int.Parse(Request["Sort"]);
            if (int.TryParse(this.Request["Sort"], out sort))
            {
                DateTime time;
                string addTime = DateTime.TryParse(this.Request["AddTime"], out time) ? this.Request["AddTime"] : null;


                Article model = this.ArticleBll.GetModel(id);
                model.Sort = sort;

                if (!string.IsNullOrEmpty(addTime))
                {
                    model.AddTime = DateTime.Parse(addTime);
                }
                if (this.ArticleBll.Update(model))
                {
                    //重新生成该栏目列表页和内容页
                    ThreadPool.QueueUserWorkItem(x =>
                    {
                        this.ResetArticle(model);
                    });
                    return OperateContext.Current.JsonModel(1, "修改成功");
                }
                else
                {
                    return OperateContext.Current.JsonModel(0, "修改失败，请重试！");
                }
            }
            else
            {
                return OperateContext.Current.JsonModel(0, "排序必须是数字，请重新输入！");
            }
        }
        #endregion

        #region 11.置顶或取消置顶文章
        /// <summary>
        /// 置顶或取消置顶文章
        /// </summary>
        /// <param name="id">文章Id</param>
        /// <returns>置顶结果</returns>
        public ActionResult SetOrCancelTop(int id)
        {
            Article model = this.ArticleBll.GetModel(id);
            //判断当前文章置顶状态
            if (model.IsTop == false || model.IsTop == null)
            {
                model.Title = string.Format("[置顶]{0}", model.Title);
                model.IsTop = true;
            }
            else
            {
                if (model.Title.Contains("[置顶]"))
                {
                    model.Title = model.Title.Replace("[置顶]", string.Empty);
                }
                model.IsTop = false;
            }
            //执行更新操作
            if (this.ArticleBll.Update(model))
            {
                //重新生成该栏目列表页和内容页
                ThreadPool.QueueUserWorkItem(x =>
                {
                    this.ResetArticle(model);
                });
                return OperateContext.Current.JsonModel(1, "操作成功！");
            }
            else
            {
                return OperateContext.Current.JsonModel(0, "操作失败，请重试！");
            }
        }
        #endregion

        #region 12.上传图片
        /// <summary>
        /// 上传图片方法
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        public ActionResult UploadImage()
        {
            //1.接收文件数据
            HttpPostedFileBase file = this.Request.Files["Filedata"];
            //2.获取文件名与文件扩展名
            string fileName = Path.GetFileName(file.FileName);
            string fileExt = Path.GetExtension(fileName);
            string streamMD5 = file.InputStream.ToMD5();    //获取文件流的MD5值
            //3.校验扩展名
            if (fileExt == ".jpg" || fileExt == ".png" || fileExt == ".gif" || fileExt == ".bmp")   //文件类型正确
            {
                #region //4.构造存储方案
                //1.构造文件夹路径
                string directory = string.Format("/UploadFiles/{0}/{1}/{2}/", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
                //2.判断目标路径是否存在，创建文件夹
                Directory.CreateDirectory(Path.GetDirectoryName(this.Server.MapPath(directory)));
                //3.构造完整存储路径，路径 + 文件流的MD5值 + 文件扩展名
                string fullDirectory = string.Format("{0}{1}{2}", directory, streamMD5, fileExt);
                #endregion

                //5.保存文件
                file.SaveAs(this.Server.MapPath(fullDirectory));

                #region //6.缩略图处理
                //1.构造缩略图存储路径
                string thumbnailPath = string.Format("{0}{1}_thumbnail{2}", directory, streamMD5, fileExt);
                //2.创建缩略图
                ImageAssistant.MakeThumbnail(this.Server.MapPath(fullDirectory), this.Server.MapPath(thumbnailPath), 300, 300, "W");
                //3.删除原图
                //System.IO.File.Delete(Server.MapPath(fullDirectory));
                #endregion

                //7.返回客户端处理结果，图片路径与缩略图路径
                return this.Content(string.Format("OK:{0}:{1}", fullDirectory, thumbnailPath));
            }
            else    //文件类型错误
            {
                //返回客户端处理结果
                return this.Content("Error:文件类型错误，请重试！");
            }
        }
        #endregion

        #region 13.上传附件
        /// <summary>
        /// 上传附件
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        public ActionResult UploadAttach()
        {
            //1.接收文件数据
            HttpPostedFileBase file = this.Request.Files["Filedata"];
            //2.获取文件名与文件扩展名
            string fileName = Path.GetFileName(file.FileName);
            string fileExt = Path.GetExtension(fileName);
            string streamMD5 = file.InputStream.ToMD5();    //获取文件流的MD5值

            #region //3.构造存储方案
            //1.构造文件夹路径
            string directory = string.Format("/UploadFiles/{0}/{1}/{2}/", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
            //2.判断目标路径是否存在，创建文件夹
            Directory.CreateDirectory(Path.GetDirectoryName(this.Server.MapPath(directory)));
            //3.构造完整存储路径，路径 + 文件流的MD5值 + 文件扩展名
            string fullDirectory = string.Format("{0}{1}{2}", directory, streamMD5, fileExt);
            #endregion

            //4.保存文件
            file.SaveAs(this.Server.MapPath(fullDirectory));
            //5.返回客户端处理结果，附件路径与附件名
            return this.Content(string.Format("OK:{0}:{1}", fullDirectory, Path.GetFileNameWithoutExtension(file.FileName)));
        }
        #endregion

        #region 14.上传视频
        /// <summary>
        /// 上传视频
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        public ActionResult UploadVideo()
        {
            //1.接收文件数据
            HttpPostedFileBase file = this.Request.Files["Filedata"];
            //2.获取文件名与文件扩展名
            string fileName = Path.GetFileName(file.FileName);
            string fileExt = Path.GetExtension(fileName);
            string streamMD5 = file.InputStream.ToMD5();    //获取文件流的MD5值
            //3.校验扩展名
            if (fileExt == ".flv" || fileExt == ".f4v")   //文件类型正确
            {
                #region //4.构造存储方案
                //1.构造文件夹路径
                string directory = string.Format("/UploadFiles/{0}/{1}/{2}/", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
                //2.判断目标路径是否存在，创建文件夹
                Directory.CreateDirectory(Path.GetDirectoryName(this.Server.MapPath(directory)));
                //3.构造完整存储路径，路径 + 文件流的MD5值 + 文件扩展名
                string fullDirectory = string.Format("{0}{1}{2}", directory, streamMD5, fileExt);
                #endregion

                //5.保存文件
                file.SaveAs(this.Server.MapPath(fullDirectory));

                //6.返回客户端处理结果，图片路径与缩略图路径
                return this.Content(string.Format("OK:{0}", fullDirectory));
            }
            else    //文件类型错误
            {
                //返回客户端处理结果
                return this.Content("Error:文件类型错误，请重试！");
            }
        }
        #endregion

        #region 15.静态页处理
        /// <summary>
        /// 静态页处理
        /// </summary>
        /// <param name="currentModel">当前文章对象</param>
        private async Task CreateHtml(Article currentModel)
        {
            //在新线程中处理
            await Task.Run(() =>
            {
                //判断内容页模板是否存在
                if (!string.IsNullOrWhiteSpace(currentModel.Channel.DetailTemplate))
                {
                    //01.生成内容静态页
                    this.CreateDetailHtml(currentModel);
                }
                else
                {
                    //如果内容页模板不存在
                    currentModel.Publish = false;
                    currentModel.Channel.SaveDirectory = null;
                    currentModel.SaveDirectory = null;
                    currentModel.FileName = null;
                    currentModel.FileExtName = null;
                    this.ChannelBll.Update(currentModel.Channel);
                    this.ArticleBll.Update(currentModel);
                }
                //判断列表页模板是否存在
                if (!string.IsNullOrWhiteSpace(currentModel.Channel.ListTemplate))
                {
                    //02.生成列表静态页
                    this.CreateListHtml(currentModel.Channel);
                }
                //03.生成聚合静态页
                this.CreateIndexHtml(currentModel.Channel);
                //04.生成首页
                this.CreateHomeHtml();
            });
        }
        #endregion

        #region 16.重新生成列表静态页
        /// <summary>
        /// 重新生成列表静态页
        /// </summary>
        /// <param name="currentChannel">当前栏目</param>
        private void RebuildListHtml(Channel currentChannel)
        {
            ThreadPool.QueueUserWorkItem(x =>
            {
                //判断列表页模板是否存在
                if (!string.IsNullOrWhiteSpace(currentChannel.ListTemplate))
                {
                    //02.生成列表静态页
                    this.CreateListHtml(currentChannel);
                }
            });
        }
        #endregion

        #region 17.全文搜索
        /// <summary>
        /// 全文搜索
        /// </summary>
        /// <returns>文章列表</returns>
        public ActionResult FullTextSearch()
        {
            //接收用户输入
            int pageIndex = string.IsNullOrEmpty(this.Request["pageIndex"]) ? 1 : int.Parse(this.Request["pageIndex"]);
            int pageSize = 20;
            string keywords = this.Request["keywords"];
            //非空校验
            if (string.IsNullOrWhiteSpace(keywords) || keywords == "请输入搜索内容")
            {
                return OperateContext.Current.JsonModel(0, "搜索关键字不可为空，请重试！");
            }
            //调用业务层查询数据并转换视图模型返回
            int pageCount, rowCount;
            List<ArticleViewForRead> list = this.ArticleBll.GetModelList(pageIndex, pageSize, out pageCount, out rowCount, keywords, keywords, null, null).Select(x => x.ToViewModel()).ToList();
            //构造分页实体对象与json实体对象
            PageModel<ArticleViewForRead> pageModel = new PageModel<ArticleViewForRead>()
            {
                Data = list,
                PageIndex = pageIndex,
                PageSize = pageSize,
                PageCount = pageCount,
                RowCount = rowCount,
            };
            //返回客户端数据
            return OperateContext.Current.JsonModel(pageModel, 1, "OK");
        }
        #endregion

        #region 18.重新生成栏目的列表页和内容页*
        /// <summary>
        /// 重新生成栏目的列表页和内容页
        /// 主要用于文章重新排序与置顶
        /// </summary>
        /// <param name="model">文章实体对象</param>
        private void ResetArticle(Article model)
        {
            //重新生成列表页
            this.CreateListHtml(model.Channel);
            //重新生成内容页
            List<Article> articleList = this.ArticleBll.GetModelList(model.ChannelId);
            articleList.ForEach(y => this.CreateDetailHtml(y));
            //重新生成首页
            this.CreateHomeHtml();
        }
        #endregion
    }
}
